package lc.q101_150;

import java.util.LinkedList;
import java.util.Queue;
import java.util.function.BiFunction;

/**
 * 给你一个 m x n 的矩阵 board ，由若干字符 'X' 和 'O' ，找到所有被 'X' 围绕的区域，并将这些区域里所有的 'O' 用 'X' 填充。
 *
 * 三种结题思路：1. 深度优先；2. 广度优先; 3. 并查集
 */
public class Q130 {

    public void solve2(char[][] board) {
        // 广度优先
        int n = board.length;
        if (n == 0) {
            return;
        }
        int m = board[0].length;
        if (m == 0) {
            return;
        }
        Queue<Integer[]> queue = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (board[i][0] == 'O') {
                queue.offer(new Integer[]{i, 0});
                board[i][0] = 'A';
            }
            if (board[i][m - 1] == 'O') {
                queue.offer(new Integer[]{i, m - 1});
                board[i][m - 1] = 'A';
            }
        }
        for (int i = 0; i < m; i++) {
            if (board[0][i] == 'O') {
                queue.offer(new Integer[]{0, i});
                board[0][i] = 'A';
            }
            if (board[n - 1][i] == 'O') {
                queue.offer(new Integer[]{n - 1, i});
                board[n - 1][i] = 'A';
            }
        }
        int[] dx = {1, -1, 0, 0};
        int[] dy = {0, 0, 1, -1};
        while (!queue.isEmpty()) {
            Integer[] poll = queue.poll();
            int x = poll[0];
            int y = poll[1];
            for (int i = 0; i < 4; i++) {
                int mx = x + dx[i];
                int my = y + dy[i];
                if (mx < 0 || my < 0 || mx >= n || my >= m || board[mx][my] != 'O') {
                    continue;
                }
                board[mx][my] = 'A';
                queue.offer(new Integer[]{mx, my});
            }
        }

        for (int i = 0; i < n; i++) {
            for (int i1 = 0; i1 < m; i1++) {
                if (board[i][i1] == 'A') {
                    board[i][i1] = 'O';
                } else if(board[i][i1] == 'O') {
                    board[i][i1] = 'X';
                }
            }
        }

    }

    public void solve(char[][] board) {
        // 深度优先题解
        int n = board.length;
        if (n == 0) {
            return;
        }
        int m = board[0].length;
        if (m == 0) {
            return;
        }
        for (int i = 0; i < n; i++) {
            dfs(board, i, 0);
            dfs(board, i, m - 1);
        }
        for (int i = 0; i < m; i++) {
            dfs(board, 0, i);
            dfs(board, n - 1, i);
        }
        for (int i = 0; i < n; i++) {
            for (int i1 = 0; i1 < m; i1++) {
                if (board[i][i1] == 'A') {
                    board[i][i1] = 'O';
                } else if (board[i][i1] == 'O'){
                    board[i][i1] = 'X';
                }
            }
        }
    }

    private void dfs(char[][] board, int x, int y) {
        if (x < 0 || y < 0 || x >= board.length || y >= board[0].length ||  board[x][y] != 'O') {
            return;
        }
        board[x][y] = 'A';
        dfs(board, x - 1, y);
        dfs(board, x, y - 1);
        dfs(board, x + 1, y);
        dfs(board, x , y + 1);
    }

}
